﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SolutionFramework.Entities;
using AbstraX.Contracts;
using VisualStudioProvider;
using System.Threading;
using System.Diagnostics;
using AbstraX.AssemblyInterfaces;
using AbstraX.ServerInterfaces;
using System.Net;
using System.IO;
using AbstraX.Bindings.Interfaces;
using CodeGenerationPipeline;
using Microsoft.Practices.Unity;
using AbstraX;
using VisualStudioProvider.Configuration;
using System.Reflection;
using Utils;
using System.Configuration;
using System.Web.Configuration;
using log4net;
using log4net.Config;
using AbstraX.QueryProviders;
using ImpromptuInterface;
using SolutionFramework.Service;
using Microsoft.ServiceModel.DomainServices.Tools;
using HydraShellServer.Contracts;
using HydraShellServer;
using Hydra.Shell;

namespace SolutionFramework.Web
{
    public class DomainHostApplication : IDomainHostApplication, IHydraPackageHost
    {
        private string imageEditorUrl;
        private string testSolutionPath;
        private Queue<string> statusMessageQueue;
        private IAssemblyProviderService assemblyProviderService;
        private Dictionary<string, IAbstraXProviderService> registeredServices;
        private IBindingsTreeCache bindingsTreeCache;
        private BindingsGenerator bindingsGenerator;
        private BindingsBuilder bindingsBuilder;
        private IEventsService eventsService;
        private Queue<BuildUIQueueEntry> buildUIQueue;
        public bool FinishBuildWithDefaults { get; set; }
        private IPipelineService pipelineService;
        private Dictionary<string, IBuildFilter> buildFilters;
        private List<IVSSolution> solutions;
        private ILog log;
        private IHydraPackageService hydraPackageService;
        public string RootPath { get; private set; }
        public string WorkspacePath { get; private set; }

        public DomainHostApplication()
        {
            XmlConfigurator.Configure();

            //if (HttpContext.Current != null)
            //{
            //    RootPath = new DirectoryInfo(HttpContext.Current.Request.PhysicalApplicationPath).Parent.FullName;
            //}
            //else
            //{
                RootPath = Path.GetFullPath("%SFSOLUTIONPATH%".Expand());
            //}

            WorkspacePath = Path.Combine(RootPath, @"CodeGenerationPipeline\Workspace\");

            //if (Environment.MachineName == "DTC2100CC9D246B")
            //{
            //    testSolutionPath = @"C:\Users\u164225\Documents\Code\nxbre-3_2_0\nxbre-3_2_0\CIODashboard.sln";
            //}
            //else
            //{
                testSolutionPath = Path.Combine(RootPath, "SolutionFramework.sln");
            //}

            var file = new FileInfo(testSolutionPath);
            
            if (!file.Exists)
            {
                Debugger.Break();
            }

            CachableQueryProvider.Log = this.Log;
            CachableQueryProvider.LogEnabled = true;
            CachableQueryProvider.EnableCaching = true;

            statusMessageQueue = new Queue<string>();
        }

        public IAbstraXDatabaseProxy DatabaseProxy
        {
            get
            {
                return new AbstraXDatabaseProxy();
            }
        }

        public IBindingsTreeCache BindingsTreeCache
        {
            get 
            {
                if (bindingsTreeCache == null)
                {
                    bindingsTreeCache = new BindingsTreeCache();
                }

                return bindingsTreeCache;
            }
        }

        public string ImageEditorUrl
        {
            get
            {
                return imageEditorUrl;
            }
            set
            {
                imageEditorUrl = value;
            }
        }

        public string GetImageEditorUrl()
        {
            return imageEditorUrl;
        }

        public List<IVSSolution> Solutions
        {
            get 
            {
                if (solutions == null)
                {
                    var solution = new VSSolution(testSolutionPath);

                    solutions = new List<IVSSolution>() { solution };
                }

                return solutions;
            }
        }

        public void SetStatus(string status)
        {
            Monitor.Enter(statusMessageQueue);
            statusMessageQueue.Enqueue(status);
            Monitor.Exit(statusMessageQueue);
        }

        public List<string> LatestStatus
        {
            get 
            {
                List<string> status = new List<string>();

                Monitor.Enter(statusMessageQueue);

                while (statusMessageQueue.Count > 0)
                {
                    status.Add(statusMessageQueue.Dequeue());
                }

                Monitor.Exit(statusMessageQueue);

                return status;
            }
        }

        public IAssemblyProviderService AssemblyProviderService 
        {
            get 
            {
                return assemblyProviderService;
            }

            set
            {
                assemblyProviderService = value;
            }
        }

        public Dictionary<string, IAbstraXProviderService> RegisteredServices
        {
            get 
            {
                if (registeredServices == null)
                {
                    registeredServices = new Dictionary<string, IAbstraXProviderService>();
                }

                return registeredServices;
            }
        }

        public IBindingsBuilder BindingsBuilder
        {
            get 
            {
                if (bindingsBuilder == null)
                {
                    bindingsBuilder = new BindingsBuilder();
                }

                return bindingsBuilder;
            }
        }

        public IBindingsGenerator BindingsGenerator
        {
            get 
            {
                if (bindingsGenerator == null)
                {
                    bindingsGenerator = new BindingsGenerator(this);
                }

                return bindingsGenerator;
            }
        }

        public IUnityContainer PipelineContainer
        {
            get 
            {
                return IoC.Container;
            }
        }

        public IEventsService EventsService
        {
            get
            {
                return eventsService;
            }

            set
            {
                eventsService = value;

                eventsService.Log = log;

                if (pipelineService != null)
                {
                    pipelineService.EventsService = eventsService;
                }

                eventsService.PostMessage(Message.SolutionOpened, this.Solutions.First().Name);
            }
        }

        public void PostEventShowUI(string uiComponentURL, string parms, IBuildUIDaemon buildUIDaemon, TimeSpan waitTimeout)
        {
            this.BuildUIQueue.Enqueue(new BuildUIQueueEntry { BuildUIDaemon = buildUIDaemon, URL = uiComponentURL });

            this.EventsService.PostMessage(new EventMessage(Message.ShowUI, uiComponentURL, parms), buildUIDaemon, waitTimeout);
        }

        public void PostEventShowUI(string uiComponentURL, string parms)
        {
            this.EventsService.PostMessage(new EventMessage(Message.ShowUI, uiComponentURL, parms));
        }

        public void PostEventBuildMessage(string message)
        {
            this.EventsService.PostMessage(new EventMessage(Message.GeneralMessage, message));
        }

        public void PostEventBuildComplete()
        {
            this.EventsService.PostMessage(new EventMessage(Message.GenerationCompleted));
        }

        public void PostEventError(string errorMessage)
        {
            this.EventsService.PostMessage(new EventMessage(Message.GeneralError, errorMessage));
        }

        public void PostEventPercentComplete(float percentComplete)
        {
            this.EventsService.PostMessage(new EventMessage(Message.PercentComplete, percentComplete));
        }

        public void ClearEventQueue()
        {
            if (this.EventsService != null)
            {
                this.EventsService.ClearQueue();
            }
        }

        public void ClearWait(bool finishWithDefaults = false)
        {
            this.FinishBuildWithDefaults = finishWithDefaults;

            this.EventsService.ClearWait();
        }

        public Queue<BuildUIQueueEntry> BuildUIQueue
        {
            get 
            {
                if (buildUIQueue == null)
                {
                    buildUIQueue = new Queue<BuildUIQueueEntry>();
                }
                
                return buildUIQueue;
            }
        }

        public IPipelineService PipelineService
        {
            get 
            {
                if (pipelineService == null)
                {
                    pipelineService = new PipelineService(this);

                    if (eventsService != null)
                    {
                        pipelineService.EventsService = eventsService;
                    }
                }

                return pipelineService;
            }
        }

        public Dictionary<string, ICodeTemplate> ProjectGroupTemplates
        {
            get 
            {
                return VSConfigProvider.ProjectGroupTemplates;
            }
        }

        public Dictionary<string, ICodeProjectTemplate> ProjectTemplates
        {
            get 
            {
                return VSConfigProvider.ProjectTemplates;
            }
        }

        public Dictionary<string, ICodeItemTemplate> ItemTemplates
        {
            get
            {
                return VSConfigProvider.ItemTemplates;
            }
        }


        public Dictionary<string, IBuildFilter> BuildFilters
        {
            get 
            {
                if (buildFilters == null)
                {
                    var filterPaths = (List<string>)ConfigurationManager.GetSection("BuildFiltersSection/BuildFilters");

                    buildFilters = new Dictionary<string, IBuildFilter>();

                    foreach (var assemblyFile in filterPaths)
                    {
                        var assembly = System.Reflection.Assembly.LoadFrom(assemblyFile);
                        var filters = assembly.GetTypes().Where(t => t.GetInterfaces().Any(i => i.Name == "IBuildFilter"));

                        // TODO - path will eventually be a user based path

                        var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                        var directory = Path.Combine(desktop, @"TestGenerator");

                        filters.Cast<Type>().ToList().ForEach(t => 
                        {
                            var filter = (IBuildFilter)Activator.CreateInstance(t, new object[] { this, directory });

                            buildFilters.Add(filter.Name, filter);
                        });
                    }
                }

                return buildFilters;
            }
        }

        public List<IProgrammingLanguage> AvailableLanguages
        {
            get 
            {
                return new List<IProgrammingLanguage>() { new CSharpLanguage() };
            }
        }

        public IHydraPackageService HydraPackageService
        {
            set 
            {
                hydraPackageService = value;
            }
        }

        public IList<ProtocolHandlerListItem> ProtocolHandlersList
        {
            get 
            {
                var handlers = hydraPackageService.GetProtocolHandlers<ProtocolHandler>().Where(p => p.Enabled == true);
                var list = new List<ProtocolHandlerListItem>();
                var directory = new DirectoryInfo(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "ClientBin"));

                if (!directory.Exists)
                {
                    Debugger.Break();
                }

                foreach (var handler in handlers)
                {
                    var codeBase = handler.CodeBase;

                    if (directory.GetFiles(codeBase).Count() > 0)
                    {
                        var file = directory.GetFiles(codeBase).First();
                        var listItem = new ProtocolHandlerListItem
                        {
                            HandlerGuid = (Guid)handler.HandlerGuid,
                            FileName = file.Name,
                            Scheme = handler.Scheme,
                            ModifiedDate = file.LastWriteTimeUtc
                        };

                        Debug.WriteLine(listItem.ModifiedDate);

                        list.Add(listItem);
                    }
                    else
                    {
                        // todo - put this back in

                        //Debugger.Break();
                    }
                }

                return list;
            }            
        }


        public IList<HydraEditorListItem> EditorList
        {
            get 
            {
                var editors = hydraPackageService.GetEditors<HydraEditor>().Where(e => e.Enabled == true);
                var list = new List<HydraEditorListItem>();

                foreach (var editor in editors)
                {
                    var listItem = new HydraEditorListItem
                    {
                        EditorID = editor.EditorID,
                        EditorName = editor.EditorName,
                        PackageGuid = editor.PackageGuid,
                        Extensions = hydraPackageService.GetEditorExtensionsForEditor<HydraEditorExtension>(editor.EditorID).Select(e => e.Extension).ToArray()
                    };

                    list.Add(listItem);
                }

                return list;
            }
        }

        public IList<HydraPackageListItem> PackageList
        {
            get 
            {
                var packages = hydraPackageService.GetPackages<HydraPackage>().Where(p => p.Enabled == true);
                var list = new List<HydraPackageListItem>();
                var directory = new DirectoryInfo(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "ClientBin"));

                if (!directory.Exists)
                {
                    Debugger.Break();
                }

                foreach (var package in packages)
                {
                    var codeBase = package.CodeBase;

                    if (directory.GetFiles(codeBase).Count() > 0)
                    {
                        var file = directory.GetFiles(codeBase).First();
                        var listItem = new HydraPackageListItem
                        {
                            PackageGuid = (Guid)package.PackageGuid,
                            FileName = file.Name,
                            ModifiedDate = file.LastWriteTimeUtc
                        };

                        Debug.WriteLine(listItem.ModifiedDate);

                        list.Add(listItem);
                    }
                    else
                    {
                        // todo - put this back in

                        //Debugger.Break();
                    }
                }

                return list;
            }
        }

        public IList<ProviderListItem> ProviderList
        {
            get 
            {
                var list = new List<ProviderListItem>();
                var items = (List<string>) System.Configuration.ConfigurationManager.GetSection("AbstraXProvidersSection/AbstraXProviders");
                var directory = new DirectoryInfo(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "ClientBin"));

                if (!directory.Exists)
                {
                    Debugger.Break();
                }

                foreach (var item in items)
                {
                    if (directory.GetFiles(item).Count() > 0)
                    {
                        var file = directory.GetFiles(item).First();
                        var listItem = new ProviderListItem
                        {
                            ID = file.Name,
                            FileName = file.Name,
                            ModifiedDate = file.LastWriteTimeUtc
                        };

                        Debug.WriteLine(listItem.ModifiedDate);

                        list.Add(listItem);
                    }
                }

                return list;
            }
        }

        public ILog Log
        {
            get 
            {
                if (log == null)
                {
                    log = LogManager.GetLogger("Web");

                    log.Info(string.Format("Web log started at {0:f}.", DateTime.Now));

                    var clientLog = LogManager.GetLogger("SolutionFramework.Views.Designer,/default.aspx");
                }

                return log;
            }
        }

        
        public IProgrammingLanguage SelectedLanguage
        {
            get 
            {
                return new
                {
                    WellKnownLanguage = WellKnownLanguage.Java
                }
                .ActLike<IProgrammingLanguage>();
            }
        }

        public bool IncludePublicMemberVariablesAsProperties
        {
            get 
            {
                return true;
            }
        }

        public IProgrammingLanguage SelectedSourceLanguage
        {
            get
            {
                return new
                {
                    WellKnownLanguage = WellKnownLanguage.CSharp
                }
                .ActLike<IProgrammingLanguage>();
            }
        }
    }
}
